package com.lnsoft.dqfs.server.handle;

import com.lnsoft.dqfs.server.dao.DqfsDao;
import com.lnsoft.dqfs.server.handle.codec.Frame;
import com.lnsoft.dqfs.server.util.Arrays16;
import com.lnsoft.dqfs.server.util.MessageUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
/**
 * 心跳处理类
 */
public class HeartBeatServerHandle extends ChannelInboundHandlerAdapter {

    private Frame frame;

    private DqfsDao dqfsDao;


    public HeartBeatServerHandle(Frame frame,DqfsDao dqfsDao) {
        this.frame = frame;
        this.dqfsDao = dqfsDao;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        log.warn("客户端{}:{},heartBeat#userEventTriggered被调用:evt:{}", frame.getClientName(), frame.getServerPort() ,evt);

        if (evt instanceof IdleStateEvent) {
            //  超时有两种情况：
            //      等待终端主发请求报文的超时，此时发送链路测试报文，超时3次没有回复，则断开链路
            //      等待终端回复确认报文的超时,此时重传请求报文，超时3次依然没有回复，则发送链路测试，如果依然超时3次则断开链路
            //
            //  每超时30s触发一次超时
            int readTimeOutNumber = frame.getReadTimeOutNumber()+1;
            final int process = frame.getProcess();

            if(readTimeOutNumber/2 >= 3){
                log.error("客户端{}:{},重新请求链路状态/测试链路，超时3次，主站主动断开链接",frame.getClientName(),frame.getServerPort());
                ctx.channel().close();
                return;
            }

            frame.setReadTimeOutNumber(readTimeOutNumber);

//            boolean finished = frame.isFinished();
            boolean finished = true;

            //  主发关闭状态下的超时
//            if (process == 0 && readTimeOutNumber%2 == 0 && !finished ) {
//                // 如果已有下发任务则不下发心跳测试帧 3次直接断开连接
//                IdleStateEvent event = (IdleStateEvent) evt;
//                log.info("客户端{}:{},数据上传完毕之前,终端超时:{}次", frame.getClientName(), frame.getServerPort(), readTimeOutNumber/2);
//                //  重置主站的状态
//                frame.setUpServerFcb(true);
//                frame.setServerFcb((byte) 0);
//                frame.getByteBuf().clear();
////                frame.setFinished(false);
//
//                byte[] bytes = new byte[6];
//                bytes[0] = 16;
//                //  请求链路状态报文
//                bytes[1] = 73;
//                bytes[2] = frame.getA1();
//                bytes[3] = frame.getA2();
//                bytes[4] = (byte) MessageUtil.createCS(bytes, 1, 4);
//                bytes[5] = 22;
//                //  备份发送报文
//                frame.setSendingFrame(bytes);
//                log.info("客户端{}:{},主站请求报文<请求链路状态>:{}", frame.getClientName(), frame.getServerPort(), Arrays16.toString(bytes));
//
//                ctx.channel().writeAndFlush(bytes);
//            }

            //  主发关闭状态下的超时
//            if (process == 0 && readTimeOutNumber%2 == 0 && finished ) {
            if (process == 0 && readTimeOutNumber%2 == 0 ) {
                log.info("客户端{}:{},主发关闭状态下的超时,终端超时:{}次", frame.getClientName(), frame.getServerPort(), readTimeOutNumber/2);
                // 如果已有下发任务则不下发心跳测试帧 3次直接断开连接
                byte[] bytes = new byte[6];
                bytes[0] = 16;
//                bytes[1] = MessageUtil.createServerC(frame, (byte) 1, (byte) 2);
                //  测试链路状态报文(不同于请求链路状态报文)
                bytes[1] = 66;
                bytes[2] = frame.getA1();
                bytes[3] = frame.getA2();
                bytes[4] = (byte) MessageUtil.createCS(bytes, 1, 4);
                bytes[5] = 22;

                ctx.channel().writeAndFlush(bytes);
                log.info("客户端{}:{},主站请求报文<测试链路状态报文>:{}", frame.getClientName(), frame.getServerPort(), Arrays16.toString(bytes));
            }

            //  主发打开状态下的超时
            if (process != 0) {
                //  补发主站下发的请求报文
                byte[] backBytes = frame.getSendingFrame();
                if (backBytes != null) {
                    ctx.channel().writeAndFlush(backBytes);
                    String info = "";
                    switch (process) {
                        case 73:
                            info = "请求链路状态";
                            break;
                        case 64:
                            info = "复位链路";
                            break;
                        case 103:
                            info = "时钟同步";
                            break;
                        case 202:
                            info = "读参数指令";
                            break;
                        case 210:
                            info = "下发写文件激活";
                            break;
                        case 2100:
                            info = "下发写文件数据";
                    }
                    log.info("客户端{}:{},主站重发请求报文<{}>:{}", frame.getClientName(), frame.getServerPort(), info, Arrays16.toString(backBytes));
                }
            }

            //  主发打开状态下超时3次，则关闭主发打开状态
            if (process != 0 && readTimeOutNumber == 3) {
                //  主发请求超时3次，停止等待确认报文
                log.info("客户端{}:{},主站请求报文超时3次，停止等待确认报文,重新请求链路状态", frame.getClientName(), frame.getServerPort());
                //  检查是否是升级过程中发生超时
                if (frame.getRecordId() != null) {
                    //  记录升级失败
                    log.info("客户端{}:{},升级失败，更新升级结果到数据库", frame.getClientName(), frame.getServerPort());
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String date = sdf.format(new Date());
                    dqfsDao.updateIacmUpgradeResult(frame.getRecordId(),date,2,frame.getOldVersion(),"下发写文件发生超时.");
                }
                frame.setProcess(0);
                frame.setReadTimeOutNumber(0);
            }
        }
        super.userEventTriggered(ctx, evt);
    }
}
